package com.xzzz.irda.auth.core.filter.impl;

import cn.hutool.core.collection.CollUtil;
import com.xzzz.irda.auth.core.constants.AuthConstant;
import com.xzzz.irda.auth.core.filter.AuthFilter;
import com.xzzz.irda.auth.core.filter.AuthFilterChain;
import com.xzzz.irda.auth.core.AuthBaseProperties;
import com.xzzz.common.base.util.SystemUtil;
import com.xzzz.common.base.util.json.JsonUtil;
import com.xzzz.common.base.util.spring.AntPathMatcherUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import javax.annotation.PostConstruct;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author wangyf
 * 
 */
@Slf4j
public class RequestLogFilter implements AuthFilter {

    /**
     * 配置文件内容
     */
    @Autowired
    private AuthBaseProperties properties;

    @Autowired
    private Environment environment;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, AuthFilterChain authFilterChain) throws IOException, ServletException {

        String requestServletPath = ((HttpServletRequest) request).getServletPath();
        //pathList为空时默认有一条数据null,判断pathList不为空且请求路径不在pathList中则不记录请求日志，直接跳过
        if (CollUtil.isNotEmpty(properties.getShowRequestLogPath()) && !properties.getShowRequestLogPath().contains("null")
                && !properties.getShowRequestLogPath().contains(requestServletPath)) {
            authFilterChain.doFilter(request, response);
            return;
        }
        //白名单接口跳过
        for (String pattern : AuthConstant.DEFAULT_WHITE_LIST) {
            if (AntPathMatcherUtil.match(pattern, requestServletPath)) {
                authFilterChain.doFilter(request, response);
                return;
            }
        }
        // 显示请求路径
        try {
            if (properties.getShowRequestUri() && !properties.getShowRequestDetail()) {
                HttpServletRequest req = ((HttpServletRequest) request);
                String url = req.getRequestURL().toString();
                log.info("[AUTHORIZ] URL: {}, IP: {}, USER-AGENT: {}", url, SystemUtil.getRemoteIp(req), req.getHeader("User-Agent"));
            }

            // 显示请求详情,此配置会覆盖显示请求路径
            if (properties.getShowRequestDetail()) {
                HttpServletRequest req = ((HttpServletRequest) request);

                Map<String, String> map = new HashMap<>();
                Enumeration<String> headerNames = req.getHeaderNames();
                while (headerNames.hasMoreElements()) {
                    String key = headerNames.nextElement();
                    String value = req.getHeader(key);
                    map.put(key, value);
                }

                //post请求约定json格式，判断是json格式才去记录requestBody的请求参数
                //这样是为了过滤post请求上传文件时记录参数日志报错
                String requestBodyParam = "";
                if (request.getContentType() != null && request.getContentType().contains("application/json")) {
                    try {
                        requestBodyParam = JsonUtil.toJsonNode(req.getReader().lines().collect(Collectors.joining(System.lineSeparator()))).toString();
                    } catch (Exception e) {
                        log.warn("请求体转换错误");
                    }
                }

                String requestHeader = "";
                try {
                    requestHeader = JsonUtil.toJsonNode(JsonUtil.toJson(map)).toString();
                } catch (Exception e) {
                    log.warn("请求头转换错误");
                }

                log.info("[AUTHORIZ] 请求详情 " +
                        ", 请求方法路径 : [{}: {}]" +
                        ", 客户端IP : [{}]" +
                        ", 请求路径参数 : [{}]" +
                        ", 请求体参数 : [{}]" +
                        ", 请求头参数 : [{}]",
                        req.getMethod(), req.getRequestURL().toString(),
                        SystemUtil.getRemoteIp(req),
                        req.getQueryString(),
                        requestBodyParam,
                        requestHeader
                );
            }
        } catch (Exception e) {
            log.warn("输出日志错误:" + e.getMessage());
        }

        authFilterChain.doFilter(request, response);
    }

    @Override
    public int getOrder() {
        return AuthConstant.Filter.LOG_FILTER;
    }

    @PostConstruct
    public void init() {
        if (AuthConstant.ENV_NAME_PROD.equals(environment.getProperty("spring.profiles.active")) && properties.getShowRequestDetail()) {
            log.warn("[AUTHORIZ] 生产环境开启请求日志会造成大量日志并对性能有一定影响,请注意配置是否需要 [auth.show-request-log:true,则会产生请求日志,auth.show-request-detail:true,会产生请求详情]");
        } else {
            log.info("[AUTHORIZ] 开启请求日志详情");
        }
    }
}
